#ifndef TABLE_INCLUDED

#include "threadsafe.h"
#include "miner.h"
#include "parser.h"
#include "url.h"
#include "db.h"
#include "htmlobject.h"
#include "xml.h"

#define FILE_SIZE 32

#define ALLSELECTED ((Selection*)1)
#include <stdlib.h>
int compare(void*,void*,int);

extern mutex *editLock;

struct recordInfo{
   int balance;
   int left;
   int right;
   int center;
   int parent;
   int centerWeight;
   int leftWeight;
   int rightWeight;
   };

#define FIELDNAMEZ	15
#define TABLENAMEZ	15
#define MAXSELECTION 256
#define MINCACHESIZE 512


struct Field{
      char fieldName[FIELDNAMEZ+1];
      char tableName[TABLENAMEZ+1];
      int type;
      int unodes;
      int size;
      int dim;
      int flags;
      int root;
      char* defaultValue;
      void *next;
      int hdOffset;
      int offset;
      };

#define FIELDSIZE (sizeof(Field)-sizeof(char*)-sizeof(void*)-2*sizeof(int))

struct queryStruct{
	Buffer	*v;
	Buffer	*to;
	Field	*f;
	Buffer	*rel;
	int m;
};


class Selection : public ThreadSafe{
   int cacheSize;
   Buffer *cache;
   ULONG accessTime;
   int pos;
   int locked;
   protected:
   char type;
   Buffer *from;
   Buffer *to;
   Field* fld;
   int order;
   int uniq;
   virtual void *getTbl() { return 0;}
   public:
   Selection () : cacheSize(0),cache(0), accessTime(getTime()),pos(0),locked(0),type(0),from(0),to(0),fld(),order(1),uniq(0){}
   Selection(Buffer* f, Buffer* t,Field* field,char typ) : cacheSize(0),cache(0),accessTime(getTime()),pos(0),locked(0),type(typ),from(f),to(t),fld(field),uniq(0){}
   ~Selection() { delete cache; delete from;delete to;}
   void cacheSelection();
   virtual int getNext(int cur,int offset,int savePos=0);
   void setOrder(int n) {order=n;}
   int isUnique(){ return uniq;}
   void setUnique(){ uniq=1;}
   int getOrder() { return order;}
   void putStore(Buffer *s) {if(cache) delete cache; cache=s; if(cache) cacheSize=s->getSize()/sizeof(int);else cacheSize=0;}
   int getStoreSize() { return cacheSize;}
   void sort();
   virtual int getTotal() { return cacheSize;}
   virtual Buffer* getBuffer();
   virtual Buffer* giveBuffer(Buffer *fromthis=0){Buffer *m=cache;cache=0;cacheSize=0;return m;}
   int getLast() {if( cache) return ((int*)((char*)*cache))[cacheSize - 1];return 0;}
   int equals(Field *f,char type,char *from,char* to=0);
   int remove(int,int);
   int add(int at, int number,int rep);
   char* getTo() {if (to) return (char*)*to;return 0;}
   char* getFrom() {if (from) return (char*)*from;return 0;}
   char getType() {return type;}
   Field *getField() {return fld;}
   void setField(Field* f) {fld=f;}
   void setAccessTime(){ accessTime=getTime()+cacheSize/(2*MINCACHESIZE);};
   ULONG getAccessTime() { return accessTime;}
   void lockSelection(int lstatus) {locked=lstatus;}
   int isLocked() { return locked;}
   };


struct FILEINFO{
   char extention[8];
   ULONG types;
   ULONG recId;
   ULONG fieldId;
   ULONG etag;
   ULONG time;
   ULONG size;
   char filename[64];
   };

struct RELATION{
   char dbname[32];
   char table[32];
   int recno;
   };

/*
typedef struct vlink{
	int recId;
	vlink* right;
	vlink* left;
}VLINK;
*/

typedef safeStruct<Field> SField;

struct CacheData{
   int recId;
   Buffer *hold;
   };



typedef struct WaitStatus{
	WaitStatus* next;
    Runnable *waitingThread;
	char waitingId[32];
} LOCWAIT;

typedef sortedList<CacheData> CacheList;

	typedef struct{
		class Table *t;
		Field *f;
	}iTable;

class Table : public URLhandler{
   int fileInfoSize;
   Selection* cachedSelection[MAXSELECTION];
   SField *fields;
   char tableName[32];
   char dbname[32];
   int headerSize;
   int nFields;
   int maxRecords;
   Buffer* defaultCache;
   int recordSize;
   CacheList *caches;
   TableFile *dbf;
   Buffer* name;
   htmlBuffer* childs;
   void getTableDef();
   void initTable();
   int elementSize(int);
   int evaluate(char* dest, htmlBuffer *string,Field *f,int recId,int fieldId);
   void evaluate(char* dest, char *string,Field *f);
   Field *fSort;
   static int cmp(const void* a,const void* b);
   htmlBuffer *makeBuffer(char* dat,Field* f,int recId=0);
   int getFieldSize(Field *f){return ((f->size*elementSize(f->type)*f->dim)+sizeof(recordInfo)+sizeof(char));}
   int getFieldOffset(Field *f){if(f) return f->offset+sizeof(recordInfo); return 0;}
   ULONG getFieldDim(char* b,Field* f) { if(f&&b) return (ULONG)b[f->offset-1]; return 0;}
   void putFieldDim(char* b,Field* f,int d) { b[f->offset-1]=(BYTE)d;}
   int searchTree(char* val,Field *f);
   int insertNode(int newRecord,Field *f,int pos=0);
   int modifyNode(int modifiedRecord,Field* modifiedField);
   int deleteNode(int newRecord,Field *f);
   int removeFiles(char *c,int recordNo, void**);
   int removeFiles(char* recbuff,Field *f,int above=0);
   int renameFiles(char* recbuff,Field *f,int below);
   SField* mkField(genericObject*);
   int modifyField(genericObject*,Field*);
   int modifyField(Field*,Field*);
   int addField(genericObject*,Field* f=0);
   int deleteField(Field*);
   Table* rename();
   void  copyTo(Table*,int);
   int backupTable();
   void sendTable(char*);
   int restoreTable();
   void addFields(Field* originalField=0,Field* newField=0,int add=0);
   void delRecordFromCache(int recId);
   char* getRecordCached(int);
   char* mustGetRecordCached(int);
   int getRecordFromCache(int,Buffer*);
   void cacheRecord(Buffer *, int);
   void setChanged(int);
   int checkTree(Field *f,int recId);
   void printTree();
   Buffer* getQueryList(Buffer* query,LinkedBuffer* &fs);
   Buffer* exportTableDef();
   Buffer *getSelectionFromCache(Field *f,char type,char *v1,char* v2=0,int* last=0);
   void removeFromSelections(int record);
   int matchSelection(char* record,Field* f, char type, char* from, char* to);
   char* translateType(Field * );
   char* getFileName(FILEINFO* f); 
   void putFileName(FILEINFO* f,File *);
   void exitTableError(int,char*);
   void clearCache();
   Selection* Sort(LinkedBuffer* &fs,Buffer* &subset);
   Selection* getUnique(queryStruct *,Buffer* subset=0,int total=0);
   void lock(){dbl->lock();}
   void release(){dbl->release();}
   void updateSelections(char* current,int recId,htmlBuffer* fieldList=0,char* old=0);


//   void newLink(VLINK* neu);
//   void remLink(VLINK* neu);
//   VLINK *head;
//   VLINK *tail;


   int waitCount;
   LOCWAIT *wt; 
   int locked;
   mutex* dbl;
   int needsRepair;
   public:
   Field *getField(char* fieldname);
   void cleanupFieldList();
   void  addSelection(Selection* x);
   Buffer* getEqualsBuffer(char* val,Field* f,LinkedBuffer* fs,int order,Buffer** r,int rec=0);
   Buffer* getEqualsBuffer(char* val,Field* f,int rec=0);
   Buffer* getEqualsBuffer(char* val,Field*,Buffer*);
   Buffer* getRangeBuffer(int start,int end,Field* f, int unique, int count,int order=0,LinkedBuffer* fs=0);
   int getNextEqual(int current,char*val,Field* f,int dir);
   int getRangeSize(char* from, char* to, char type,Field *f,int* fromRec, int* toRec);
   void hidePSWD();
   enum {MAXFIELDS = 128};
   enum {CHAR_TYPE=1,INT_TYPE=2,TIME_TYPE=3,FILE_TYPE=4,INDEX_TYPE=5,REAL_TYPE=6,BIN_TYPE=12,NEWFILE_TYPE=10};
   enum{NORMAL=0,UNIQUE=1,MANDATORY=2,KEY=3,UNSIGNED_INT=4,LOCAL=8,SYSTEM=16,HIDDEN=32,BINARY_DATA=64};
   Table(char* db,char* tname); 
   Table(char* tname); 
   Table(TableFile*);
   Field *getField(int);
   int createTableFile();
   void setBinType(int n);
   int moveNode(int move,int pos,char* fieldName);
   int insertRow(genericObject* , int system=0 );
   int updateRecord(genericObject*, int,int system=0);
   void deleteRecord(int recordNo,htmlBuffer *from=0,int mdel=0);
   int freeCache(int size, ULONG *age);
   int exists();
   int exists(int);
   int textField(char* fldname);
   ~Table();
   int operator[] (int n){  if (dbf) return (*dbf)[n]; return 0;}
   int getTotal() { if(dbf) return dbf->getTotal()-1;return 0;}
   int getNext(int rec, int offset) { if(dbf) return dbf->getNext(rec,offset); return 0;}
   char* flagList(int);
   int addField(char* fieldName,int fieldSize,int fieldType,int fieldDim,int flags,char * defaultValue=0,int ok=0);
   int getRecordSize();
   int getHeaderSize() { if (recordSize==0) getRecordSize();return headerSize; }
   int tablecmp(char* tname) { return stricmp(*name,tname); }
   int getKeyRecord(char*field,char*val);
   Selection* getSelection(int cid,Buffer* query, Buffer* selectfrom=0,int add=0);
   char* getTableName() { return tableName;}
   char* getDbName() {return dbname;}
   int getSortType() { if(fSort) return fSort->type; return 0; }
   int getSortField() { return(getFieldOffset(fSort));}
   Buffer* search(Info*);
   htmlBuffer* getValue(int cid,int recordId,char* recordName);
   htmlBuffer* getFieldValue(int recordId,char* recordName,Field *f=0);
   void output(genericObject*,Runnable*,File*);
   int charWidth(Field *f);
   void setMaxRecord(int m) { maxRecords=m; }
   genericObject* exportData(int recno,htmlBuffer *flist,int tableDef);
   int importData(genericObject*);
   int makeTable(htmlBuffer*);
   int makeTable(xmlObject*);
   int lockTable(int rec,char *id,Runnable* thread,int locknow);
   int unlockTable(int rec,char* id);
   void rebuildSearch();
   void RepairTable(int files=0);
   void RepairTableOnline();
   void list();
   int getEquals(char* val,Field *f);
   Buffer* getVal(char* , Field *);
   int getNextRangeAsc(int,Field*,int);
   int getNextRangeDesc(int,Field*,int);
   int getMax(Field *f);
   int getMin(Field *f);
   int getLastEqual(int,Field*);
   int isChild(char*);
   void deleteRelation(char*relField,int relation);
   void addChild(htmlBuffer*);
   void removeChild(char*);
   Selection* selectByRelation(int cid,Field* f, Buffer* query);
   Selection* madSearch(char* string,Buffer *set,Field* f);
   int getFieldAny(queryStruct* qx,char* fieldname);//,LinkedBuffer* sp=0,int cid=0);
   File* getTableInfo(int remake=0);
   void DeleteCachedRecord(int );
   void FreeCachedRecord(int );
   void getTableName(char *s){snprintf(s,512,"%s.%s",dbname,tableName);}
   void *getAvlTree(Selection *s,LinkedBuffer *fs);
   iTable* getParent(char*,int,LinkedBuffer * &t);
   int getRecordNo(LinkedBuffer*,int);
   int compareRecords(int recA,int recB,Field *);
   char *getpath(){if(name) return *name;return "NA";}
   };


#define SEND_WHOLE_RECORD -1
#define SEND_TABLE_DEFINITION -2
#define INVALID_RECORD  -3
#define INVALID_RESPONSE  -4
void freeSomeCache(Table*,int,ULONG*);
void caravanlog(char* s);
extern  char* sUSERID;
extern char* sPSWD;
#define PSWDl 9
extern char* sDESTINATIONS;
#define lDESTINATIONS 14
extern char* sTIME;
#define lTIME 6
extern char* sPRIORITY;
#define lPRIORITY 9
extern char* sTABLE;
#define lTABLE 7
extern char* sDBNAME;
#define lDBNAME 8
extern char* sACKTIME;
#define lACKTIME 9
extern char* sRECORD;
#define lRECORD 8
extern char* sFIELDS;
#define lFIELDS  8
extern char* sWHOLE;
#define lWHOLE 7
extern char* sDEFINITION;
#define lDEFINITION 12
extern char* sORIGIN;
#define lORIGIN 10
extern char* sRECID;
#define lRECID 7
extern char* sALL;
extern char* sFROM;
extern char* sTABLEDEF;
#define lTABLEDEF 10
extern char* sDB;
extern char* sRESPONSE;
extern char* sSERVER;
extern char* FTPHOME;
extern char* sDOMAIN;
extern char* sDELIM;
extern char* sMSGID;
extern char* sQUEUEID;
#define DELIMl 6
#define DOMAINl 7
#define TABLE_INCLUDED
#define RESPONSEl 10
#endif



